using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Text;
using Decav.Gatsb.Mobile;

namespace Decav.Gatsb.Application.CommandWorkflow
{
    /// <summary>
    /// Finds a particular location.
    /// </summary>
	public partial class FindLocationCommandActivity: SequenceActivity
	{
		public FindLocationCommandActivity()
		{
			InitializeComponent();
            MakeSelectionString = "Reply with # of your choice";
		}

        /// <summary>
        /// The dependency property that gets or sets the query text.
        /// </summary>
        public static DependencyProperty QueryTextProperty = DependencyProperty.Register(
            "QueryText", typeof(string), typeof(FindLocationCommandActivity));

        /// <summary>
        /// Gets or sets the query text.
        /// </summary>
        [ValidationOption(ValidationOption.Required)]
        public string QueryText
        {
            get { return (string)GetValue(QueryTextProperty); }
            set { SetValue(QueryTextProperty, value); }
        }

        /// <summary>
        /// The dependency property that gets or sets the string used that prompts a user to make a selection.
        /// </summary>
        public static DependencyProperty MakeSelectionStringProperty = DependencyProperty.Register(
            "MakeSelectionString", typeof(string), typeof(FindLocationCommandActivity));

        /// <summary>
        /// Gets or sets the string used that prompts a user to make a selection.
        /// </summary>
        public string MakeSelectionString
        {
            get { return (string)GetValue(MakeSelectionStringProperty); }
            set { SetValue(MakeSelectionStringProperty, value); }
        }
        

        /// <summary>
        /// The dependency property that gets or sets the location that was found.
        /// </summary>
        public static DependencyProperty LocationProperty = DependencyProperty.Register(
            "Location", typeof(Location), typeof(FindLocationCommandActivity));

        /// <summary>
        /// Gets or sets the location that was found.
        /// </summary>
        public Location Location
        {
            get { return (Location)GetValue(LocationProperty); }
            set { SetValue(LocationProperty, value); }
        }

        /// <summary>
        /// The dependency property that gets or sets if a "none of the above" option should be added that creates a new location.
        /// </summary>
        public static DependencyProperty NoneOfTheAboveVisibleProperty = DependencyProperty.Register(
            "NoneOfTheAboveVisible", typeof(bool), typeof(FindLocationCommandActivity));

        /// <summary>
        /// Gets or sets if a "none of the above" option should be added that creates a new location.
        /// </summary>
        public bool NoneOfTheAboveVisible
        {
            get { return (bool)GetValue(NoneOfTheAboveVisibleProperty); }
            set { SetValue(NoneOfTheAboveVisibleProperty, value); }
        }
        

        private string _locationsFoundMessage;

        /// <summary>
        /// The message sent when many locations are found.
        /// </summary>
        public string LocationsFoundMessage
        {
            get { return _locationsFoundMessage; }
        }

        private void setDiscoveredLocation_ExecuteCode(object sender, EventArgs e)
        {
            Location = findLocations.Locations[0];
        }


        #region Build Many Message
        private void buildMessage_ExecuteCode(object sender, EventArgs e)
        {
            // We found lots of locations, so we need to choose one.... Send a message back and ask which one.
            StringBuilder builder = new StringBuilder();
            builder.Append("Results:\r\n");

            CreateLocationList(builder, findLocations.Locations, MakeSelectionString.Length, NoneOfTheAboveVisible);

            builder.Append(MakeSelectionString);

            _locationsFoundMessage = builder.ToString();
        }

        private const string _noneOfAbove = "0) [Not listed]\r\n";

        /// <summary>
        /// Creates a list of locations from an array.
        /// </summary>
        /// <param name="builder">The string builder to append to.</param>
        /// <param name="locations">The array of locations to write.</param>
        /// <param name="additionalCharCount">The other characters to take into account that will be added after.</param>
        /// <param name="addOtherOption">Adds the "none of the above" option as option "0" to the list.</param>
        public static void CreateLocationList(StringBuilder builder, Location[] locations, int additionalCharCount, bool addOtherOption)
        {
            if (builder == null)
                throw new ArgumentNullException("builder");

            if (locations == null)
                throw new ArgumentNullException("locations");

            if (addOtherOption)
                additionalCharCount += _noneOfAbove.Length;

            for (int i = 0; i < locations.Length; i++)
            {
                string name = locations[i].ToString(LocationNameFormat.MobileTextMessage);
                string entry = string.Format("{0}) {1}\r\n", i + 1, name);

                if (builder.Length + entry.Length + additionalCharCount > MaxTextMessageLength)
                {
                    break;
                }

                builder.Append(entry);
            }

            if (addOtherOption)
                builder.Append(_noneOfAbove);
        }
        #endregion

        private void parseUserResponse_ExecuteCode(object sender, EventArgs e)
        {
            Console.WriteLine("Parsing user response");
            MobileMessage response = waitManyResponse.UserResponse;
            
            string message = response.Body.Trim();

            int i = 0;
            if (!Int32.TryParse(message, out i))
                throw new InvalidUserResponseException("The user responded with a non-numeric answer to a choice of locations.");

            if (i == 0 && NoneOfTheAboveVisible)
            {
                Location = null;
                return;
            }

            if (findLocations.Locations.Length < i)
                throw new InvalidUserResponseException("The user response was out of the range of locations that were found.");

            i--; // get back down to zero based index.

            // Get the correct location.
            Location = findLocations.Locations[i];
        }


        public const int MaxTextMessageLength = 160;

        private void setNewTempLocation_ExecuteCode(object sender, EventArgs e)
        {
            Location = createNewTempLocationActivity2.Location;
        }

        private void setNewTempLocationNoLoc_ExecuteCode(object sender, EventArgs e)
        {
            Location = createNewTempLocationActivity1.Location;
        }

    }
}
